package com.livestocksolutions.ui;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;

import com.livestocksolutions.Bovine;
import com.livestocksolutions.Bull;
import com.livestocksolutions.Cow;
import com.livestocksolutions.Group;
import com.livestocksolutions.Join;
import com.livestocksolutions.LivestockSolutions;
import com.livestocksolutions.Mob;
import com.livestocksolutions.util.BovineList;
import com.livestocksolutions.util.Comparators;
import com.livestocksolutions.util.JDatePickerDate;
import com.livestocksolutions.util.Table;

import javax.swing.DefaultComboBoxModel;
import javax.swing.border.EmptyBorder;

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

/**
 * Show list and details relating to a Joining stored in the system to the user.
 * @author Ken DeVries
 * @author Adam Parr
 * 
<<<<<<< HEAD
 * @.modified 19 March 2013
=======
 * @.modified 18 March 2013
>>>>>>> branch 'master' of https://parr.adam@code.google.com/p/livestocksolutionscattlemanagementsystem/
 */
public class JoiningPanel extends JPanel implements TabbedInterface {
	private static final long serialVersionUID = 1L;
	
	/**
	 * The initial view for this tab.
	 * Shows all Joinings that are in the system.
	 */
	public static final int JOINING_LIST = 0;
	/**
	 * To create a new Joining.
	 */
	public static final int VIEW_NEW_JOINING=1;

	/**
	 * The default View when selecting a Group or Mob to show in detail.
	 */
	public static final int VIEW=3;
	/**
	 * Shows Details of the selected Joining and also any Members for that Mob or Group.
	 */
	public static final int VIEW_MEMBER = 7;
	
	/**
	 * The current view.
	 * 
	 * @see #JOINING_LIST
	 * @see #VIEW_NEW_JOINING
	 * @see #VIEW
	 * @see #VIEW_MEMBER
	 */
	protected int viewing = -1;

	/**
	 * The ID of the Joining we are Viewing
	 */
	protected long joiningViewID = -1;
	/**
	 * Mob id, if applying a Joining to a Mob
	 */
	protected long mobID = -1;
	
	/**
	 * Determine if the editable details of a Joining is editable.
	 */
	protected boolean edit = false;

	protected ArrayList<BovineList<Bovine>> bovineArray = new ArrayList<BovineList<Bovine>>();
	
	private JComboBox bullList;
	private JDatePickerDate entryDate = null;
	private JDatePickerDate exitDate = JDatePickerDate.createJDatePicker();
	
	/**
	 * The list of Cows to add to the current Joining
	 */
	private ArrayList<Cow> cowAddList = new ArrayList<Cow>();
	/**
	 * The Bull that is provided to be selected.
	 */
	private Bull bull;
	
	/**
	 * This panel becomes the viewport of {@link #jsp}
	 */
	protected final JPanel panel = new JPanel();
	/**
	 * The Panel where the innerlist for a particular item will rest.
	 */
	protected JTabbedPane jisp = new JTabbedPane();
	/**
	 * Where the data for all members for a particular Joining will be shown.
	 */
	protected final JPanel membersListPanel = new JPanel();
	/**
	 * Where the data for all the ability to add members for a particular Joining will be shown.
	 */
	protected final JPanel memberAddListPanel = new JPanel();
	
	/**
	 * Sort the member list by Visual ID tag.
	 */
	protected static final int LIST_ORDER_VISUAL = 0;
	/**
	 * Sort the member list by using NLIS ID.
	 */
	protected static final int LIST_ORDER_NLIS = 1;
	/**
	 * Sort the member list by using RF ID.
	 */
	protected static final int LIST_ORDER_RF 	= 2;
	/**
	 * Sort the member list by DOB.
	 */
	protected static final int LIST_ORDER_DOB 	= 3;
	/**
	 * Sort the member list by active status.
	 */
	protected static final int LIST_ORDER_ACTIVE= 4;
	/**
	 * Sort the joining list by using bull entry date.
	 */
	protected static final int LIST_ORDER_ENTRY = 0;
	/**
	 * Sort the joining list by using bull exit date.
	 */
	protected static final int LIST_ORDER_EXIT = 1;
	/**
	 * Sort the joining list by using bull visual ID.
	 */
	protected static final int LIST_ORDER_BULL = 2;
	/**
	 * Sort the joining list by using number of cows in the join.
	 */
	protected static final int LIST_ORDER_COW_COUNT= 3;

	/**
	 * The current member list order method.
	 * @see #LIST_ORDER_VISUAL
	 * @see #LIST_ORDER_NLIS
	 * @see #LIST_ORDER_RF
	 * @see #LIST_ORDER_DOB
	 * @see #LIST_ORDER_ACTIVE
	 */
	protected int orderMemberListBy = LIST_ORDER_VISUAL;
	
	/**
	 * The joining list order method.
	 * @see #LIST_ORDER_ENTRY
	 * @see #LIST_ORDER_EXIT
	 * @see #LIST_ORDER_BULL
	 * @see #LIST_ORDER_COW_COUNT
	 */
	protected int orderJoiningListBy = LIST_ORDER_VISUAL;
	/**
	 * The sort direction. Ascending : 1, Descending -1;
	 */
	protected int orderMobHighToLow = 1, orderGroupHighToLow = 1, orderObservationHighToLow = 1, orderMemberHighToLow = 1, orderJoiningHighToLow = 1;
	
	/**
	 * Constructor
	 */
	public JoiningPanel(){
		JScrollPane jsp = new JScrollPane();
		setLayout(new BorderLayout(0, 0));
		jsp.setViewportView(panel);
		jsp.setViewportBorder(BorderFactory.createEmptyBorder());
		add(jsp);
		
		AdjustmentListener al = new AdjustmentListener(){
			@Override
			public void adjustmentValueChanged(AdjustmentEvent evt) {
				panel.repaint();
			}
		};
		jsp.getHorizontalScrollBar().addAdjustmentListener(al);
		jsp.getVerticalScrollBar().addAdjustmentListener(al);
	}
	
	@Override
	public void displayPanel(){
		int panel = viewing;
		if(viewing==JOINING_LIST) {
			viewing=-1;
			panel = JOINING_LIST;
		}
		displayPanel(panel);
	}
	
	/**
	 * @see #JOINING_LIST
	 * @see #VIEW
	 * @see #VIEW_NEW_JOINING
	 * @see #VIEW_MEMBER
	 */
	@Override
	public void displayPanel(int panel){
		switch(panel){
			case JOINING_LIST:
				if(viewing!=JOINING_LIST){
					createMainPanel();
				}
				break;

			case VIEW_NEW_JOINING:
				if(viewing!=VIEW_NEW_JOINING){
					createJoiningPanel(-1,mobID);
				}
				break;
			case VIEW:
			case VIEW_MEMBER:
				createJoiningPanel(joiningViewID,mobID);
				break;
			default:
				createMainPanel();
		}
	}
	
	/**
	 * The Joining list, containing all Joinings in the System.
	 */
	private void createMainPanel(){
		viewing = JOINING_LIST;
		joiningViewID = 0;
		panel.setLayout(new BorderLayout(0, 0));
		
		final int BULL_IN 	= 0;
		final int BULL_OUT	= 1;
		final int BULL 		= 2;
		final int COUNT		= 3;
		
		final Table joiningPanel = new Table("Joinings",false,
			"Bull Entry Date","Bull Exit Date","Bull Visual ID","No. Members");
		joiningPanel.setEmptyMessage("There are no Joinings to show.");
		
		new Thread(){
			@Override
			public void run(){
				while(!LivestockSolutions.isReady()){
					try {
						sleep(500);
					} catch (InterruptedException e) {}
					if(LivestockSolutions.close){
						return;
					}
				}
				
				joiningPanel.setHeaderOrderedBy(orderJoiningListBy==LIST_ORDER_ENTRY?BULL_IN:orderJoiningListBy==LIST_ORDER_EXIT?BULL_OUT:orderJoiningListBy==LIST_ORDER_BULL?BULL:orderJoiningListBy==LIST_ORDER_COW_COUNT?COUNT:BULL_IN, orderJoiningHighToLow==1);
				joiningPanel.addHeaderMouseListener(BULL_IN, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderJoiningHighToLow = orderJoiningHighToLow*(orderJoiningListBy==LIST_ORDER_ENTRY?-1:1);
						orderJoiningListBy = LIST_ORDER_ENTRY;
						createMainPanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				joiningPanel.addHeaderMouseListener(BULL_OUT, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderJoiningHighToLow = orderJoiningHighToLow*(orderJoiningListBy==LIST_ORDER_EXIT?-1:1);
						orderJoiningListBy = LIST_ORDER_EXIT;
						createMainPanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				joiningPanel.addHeaderMouseListener(BULL, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderJoiningHighToLow = orderJoiningHighToLow*(orderJoiningListBy==LIST_ORDER_BULL?-1:1);
						orderJoiningListBy = LIST_ORDER_BULL;
						createMainPanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				joiningPanel.addHeaderMouseListener(COUNT, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderJoiningHighToLow = orderJoiningHighToLow*(orderJoiningListBy==LIST_ORDER_COW_COUNT?-1:1);
						orderJoiningListBy = LIST_ORDER_COW_COUNT;
						createMainPanel();
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				Join[] jList = LivestockSolutions.getJoinings();
				Arrays.sort(jList,
					orderJoiningListBy==LIST_ORDER_ENTRY?
						orderJoiningHighToLow==1?Comparators.joiningComparatorEntry:Collections.reverseOrder(Comparators.joiningComparatorEntry)
					:orderJoiningListBy==LIST_ORDER_EXIT?
						orderJoiningHighToLow==1?Comparators.joiningComparatorExit:Collections.reverseOrder(Comparators.joiningComparatorExit)
					:orderJoiningListBy==LIST_ORDER_BULL?
						orderJoiningHighToLow==1?Comparators.joiningComparatorBull:Collections.reverseOrder(Comparators.joiningComparatorBull)
					:orderJoiningHighToLow==1?Comparators.joiningComparatorCowCount:Collections.reverseOrder(Comparators.joiningComparatorCowCount));

				for(int x=0; x<jList.length; x++){
					joiningPanel.addRow(
						new JLabel(JDatePickerDate.format(jList[x].getInsertionDate())),
						new JLabel(jList[x].getRemovalDate()!=null?JDatePickerDate.format(jList[x].getRemovalDate()):"Still Active"),
						new JLabel(jList[x].getBull().getEartag().getEartagID()),
						new JLabel(jList[x].getCows()!=null?String.valueOf(jList[x].getCows().length):"0"));
					
					final long id = jList[x].getID();
					joiningPanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							if(createJoiningPanel(id)){
								//Show message not found?
							}
						}
						@Override public void mousePressed(MouseEvent e) { }
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				panel.validate();
			}
		}.start();
		
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel = new JPanel();
		((FlowLayout)buttonPanel.getLayout()).setAlignment(FlowLayout.RIGHT);
		
		JButton btnNewJoining = new JButton("New Joining");
		btnNewJoining.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				entryDate=null;
				createJoiningPanel(-1L);
			}
		});
		
		panel.removeAll();
		buttonPanel.add(btnNewJoining);
		container.add(buttonPanel,BorderLayout.NORTH);
		container.add(joiningPanel,BorderLayout.CENTER);
		panel.add(container,BorderLayout.NORTH);
		panel.repaint();
	}
	
	/**
	 * Create the elements to display details of the joining with the given ID.
	 * @param joiningID The id of the joining to show details for, if the value is -1,
	 * then this will create a new joining.
	 * @param bovine The Cattle to add to this Joining, including a Bull Bovine, when joiningID
	 * is -1 then this Bull will become the bull of this Join. all other Cows in the given list
	 * will be added as members.
	 * @return <tt>true</tt> if the Joining at the given id existed, <tt>false</tt> otherwise
	 */
	public boolean createJoiningPanel(long joiningID, Bovine... bovine){
		for(Bovine b : bovine){
			if(b.getGender().equals(Bull.GENDER)){
				bull=(Bull)b;
			}
			if(b.getGender().equals(Cow.GENDER) && !cowAddList.contains(b)){
				cowAddList.add((Cow)b);
			}
		}
		joiningViewID = joiningID;
		mobID = -1;
		boolean val = true;
		if(!cowAddList.isEmpty()){
			edit=true;
		}else{
			val = createJoiningPanel(joiningID,-1);
		}
		return val;
	}
	
	/**
	 * Create the elements to display details of the joining with the given ID.
	 * @param joiningID The id of the joining to show details for, if the value is -1,
	 * then this will create a new joining.
	 * @return <tt>true</tt> if the Joining at the given id existed, <tt>false</tt> otherwise
	 */
	public boolean createJoiningPanel(long joiningID){
		return createJoiningPanel(joiningID,-1);
	}
	/**
	 * Create the elements to display details of the joining with the given ID.
	 * If mobID is not -1 then automatically apply this joining to the given Mob, or if
	 * joiningID is -1 then allow the creation of the joining, then apply to the Mob.
	 * @param joiningID The id of the joining to show details for, if the value is -1,
	 * then this will create a new joining.
	 * @param mobID The Mob which will have this Joining applied to.
	 * @return <tt>true</tt> if the Joining at the given id existed, <tt>false</tt> otherwise
	 */
	public boolean createJoiningPanel(final long joiningID, final long mobID){
		long previousJoiningViewID = joiningViewID;
		if(joiningViewID != joiningID){
			this.mobID = mobID;
			viewing=VIEW;
			joiningViewID = joiningID;
			if(jisp.getParent()!=null)
				jisp.getParent().remove(jisp);
			jisp = new JTabbedPane();
			
			edit=false;
			entryDate = entryDate==null?JDatePickerDate.createJDatePicker():entryDate; 
			entryDate.setDate("-1");
		}
		
		/**
		 * The Joining that is being shown.
		 */
		JButton btnHome = new JButton("Joining List");
		btnHome.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				edit=false;
				bull=null;
				cowAddList.clear();
				entryDate=null;
				jisp.remove(memberAddListPanel);
				displayPanel(JOINING_LIST);
			}
		});
		panel.removeAll();
		panel.setLayout(new BorderLayout(10, 10));
		JPanel buttonMenuLeft = new JPanel();
		JPanel buttonMenuRight = new JPanel();
		((FlowLayout)buttonMenuLeft.getLayout()).setAlignment(FlowLayout.LEFT);
		((FlowLayout)buttonMenuRight.getLayout()).setAlignment(FlowLayout.RIGHT);
		buttonMenuLeft.add(btnHome);
		
		JPanel container = new JPanel();
		container.setLayout(new BorderLayout(10, 10));
		JPanel flowPanel = new JPanel();
		JPanel panel_1 = new JPanel();
		panel_1.setLayout(new BorderLayout(0, 10));
		
		JPanel buttonMenu = new JPanel();
		buttonMenu.setLayout(new BorderLayout());
		buttonMenu.add(buttonMenuLeft,BorderLayout.WEST);
		buttonMenu.add(buttonMenuRight,BorderLayout.EAST);
		container.add(buttonMenu,BorderLayout.NORTH);
		flowPanel.add(panel_1);
		container.add(flowPanel,BorderLayout.CENTER);
		panel.add(container,BorderLayout.NORTH);
		
		boolean valid = true;
		final Join joining = LivestockSolutions.getJoiningByID(joiningID);
		if(joining!=null || joiningID==-1){
			
			JButton btnCancel = new JButton(joiningViewID!=-1?"Cancel":"Clear");
			btnCancel.setVisible(edit);
			btnCancel.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					edit=false;
					entryDate=null;
					cowAddList.clear();
					bull=null;
					jisp.remove(memberAddListPanel);
					JoiningPanel.this.mobID=-1;
					displayPanel(viewing);
				}
			});
			
			JButton btnCreateSave = new JButton(joiningViewID==-1?"Create":edit?"Save":"Edit");
			btnCreateSave.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					if(edit){
						Join j = LivestockSolutions.getJoiningByID(joiningViewID);
						Date jDate = entryDate.getDate();

						if(jDate!=null && !jDate.after(new Date())){
							if(j==null){
								if(bullList.getSelectedIndex()>=0){
									j = new Join(jDate,(Bull)(bovineArray.get(bullList.getSelectedIndex())).getItem());
								}else{
									JOptionPane.showMessageDialog(JoiningPanel.this, "The Bull for this Join is not correct", "Joining incorrect" , JOptionPane.OK_OPTION);
									return;
								}
							}
							Date jEDate = exitDate.getDate();
							if(jEDate==null && !exitDate.isEmpty()){
									JOptionPane.showMessageDialog(JoiningPanel.this, "The Bull Out date for this Join is invalid", "Entry date for Joining incorrect" , JOptionPane.OK_OPTION);
							}
							
							if(jEDate!=null){
								j.setRemovalDate(jEDate);
							}
							
							Group g = LivestockSolutions.getGroupByID(mobID);
							
							if(LivestockSolutions.addJoining(j)){
								for(Cow c : cowAddList){
									j.addCow(c);
								}
								if(mobID!=-1 && g != null){
									g.applyJoiningToMob(j);
									if(g instanceof Mob) {
										MainFrame.getInstance().showMob(mobID);
									}else {
										MainFrame.getInstance().showGroup(mobID);
									}
								}
								JoiningPanel.this.joiningViewID=j.getID();
								entryDate=null;
								edit=!edit;
								cowAddList.clear();
								JoiningPanel.this.mobID=-1;
								jisp.remove(memberAddListPanel);
								if(bull!=null){
									MainFrame.getInstance().showBovine(bull.getID());
									bull=null;
								}
								viewing = VIEW;
							}else{
								JOptionPane.showMessageDialog(JoiningPanel.this, "Failed to create Joining", "Failed to create Joining" , JOptionPane.OK_OPTION);
							}
						}else{
							if(jDate!=null && jDate.after(new Date())){
								JOptionPane.showMessageDialog(JoiningPanel.this, "To create this Joining, The Bull entry date must be a date in the past", "Future Entry date for Joining" , JOptionPane.OK_OPTION);
							}else{
								JOptionPane.showMessageDialog(JoiningPanel.this, "To create this Joining, A Bull entry date must be set", "No Entry date for Joining" , JOptionPane.OK_OPTION);
							}
						}
					}else{
						entryDate=null;
						edit=!edit;
						bull=null;
						cowAddList.clear();
						jisp.remove(memberAddListPanel);
					}
					displayPanel(viewing);
				}
			});
			
			buttonMenuRight.add(btnCreateSave);
			buttonMenuRight.add(btnCancel);
			
			JPanel joiningDetails = new JPanel();
			JButton btnBull = null;
			if(bullList==null){
				bullList = new JComboBox();
			}
			if(bull==null){
				Bovine[] tBovineArray = LivestockSolutions.getBovines();
				bullList.setEnabled(true);
				Arrays.sort(tBovineArray,Comparators.bovineComparatorVISID);
				for(Bovine b : tBovineArray) {
					BovineList<Bovine> bli = new BovineList<Bovine>(b);
					if(!bovineArray.contains(bli)){
						bovineArray.add(bli);
					}
				}
			}else{
				bovineArray = new ArrayList<BovineList<Bovine>>();
				bullList.setEnabled(false);
				BovineList<Bovine> bli = new BovineList<Bovine>(bull);
				if(!bovineArray.contains(bli)){
					bovineArray.add(bli);
				}
			}
			Date joinDate = null;
			Date joinEnd = null;
			
			boolean refresh=false;
			if(entryDate!=null&&!entryDate.getText().equals("-1")){
				refresh=true;
			}else{
				entryDate=JDatePickerDate.createJDatePicker(); 
			}
			
			if(!refresh){
				jisp.setOpaque(false);
				jisp.setBorder(new EmptyBorder(0,0,0,0));
				jisp.addTab("Members",MainFrame.scale(MainFrame.getImageIcon(MainFrame.CATTLE_LIST),MainFrame.ICON_WIDTH,MainFrame.ICON_HEIGHT), membersListPanel);
				jisp.addMouseListener(new MouseListener(){
					@Override public void mouseClicked(MouseEvent e) {}
					@Override public void mousePressed(MouseEvent e) {
						new Thread(){@Override
						public void run(){
							if(jisp.getSelectedComponent()==membersListPanel)
								createMembersPanel(joiningID);
						}}.start();
					}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});

				jisp.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
				jisp.setAutoscrolls(true);
				
				jisp.setBorder(new EmptyBorder(0,0,0,0));
			}
			panel.add(jisp,BorderLayout.CENTER);
			
			if(joining!=null){
				btnBull = new JButton(joining.getBull().getEartag().getEartagID()+" - "+joining.getBull().getEartag().getRfID());
				btnBull.addActionListener(new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						if(!MainFrame.getInstance().showBovine(joining.getBull().getID())){
							//Show message not found?
						}
					}
				});
				joinDate = joining.getInsertionDate();
				joinEnd = joining.getRemovalDate();
			}else{
				if(joiningID==-1){
					joinDate = new Date();
					edit=true;
				}
				if(bovineArray.size()>0){
					Iterator<BovineList<Bovine>> it = bovineArray.iterator();
					while(it.hasNext()){
						Bovine b = it.next().getItem();
						if(!(b instanceof Bull && b.isActive())){
							it.remove();
						}
					}
				}

				if(bovineArray.size()==0){
					joiningViewID=previousJoiningViewID;
					this.mobID=-1;
					valid = false;
				}

				Object selectedBull = bullList.getSelectedItem();
				bullList.setModel(new DefaultComboBoxModel(bovineArray.toArray()));
				if(bullList.getItemCount()<=0){
					valid = false;
				}else{
					if(selectedBull==null){
						bullList.setSelectedIndex(0);
					}else{
						bullList.setSelectedItem(selectedBull);
					}
				}

			}
			
			JPanel addGroupPanel = new JPanel();
			addGroupPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
			
			JLabel lblAction = new JLabel(joiningID==-1?"Add Joining":(edit?"Edit":"Show")+" Joining Details");
			addGroupPanel.add(lblAction);
			panel_1.add(addGroupPanel, BorderLayout.NORTH);
			panel_1.add(joiningDetails, BorderLayout.CENTER);
			
			entryDate.setEnabled(joiningID==-1);	
			exitDate.setEnabled(joining==null?edit:joining.getRemovalDate()==null?edit:false);
			
			if(!refresh){
				entryDate.setDate(joinDate);
				exitDate.setDate(joinEnd);
			}
			
			JPanel bullDetailsPanel = new JPanel();
			bullDetailsPanel.setLayout(new BorderLayout(10, 0));
			
			JLabel lblBull = new JLabel("Bull");
			bullDetailsPanel.add(lblBull, BorderLayout.WEST);
			
			bullDetailsPanel.add(btnBull!=null?btnBull:bullList, BorderLayout.CENTER);
			
			JPanel datePanel = new JPanel();
			datePanel.setLayout(new BorderLayout(0, 0));
			
			JPanel entryPanel = new JPanel();
			datePanel.add(entryPanel, BorderLayout.WEST);
			
			JLabel lblEntry = new JLabel("Entry Date");
			entryPanel.add(lblEntry);
			
			JPanel entryDateField = new JPanel();
			entryPanel.add(entryDateField);
			entryDateField.setLayout(new BorderLayout(0, 0));

			entryDateField.add(entryDate);
			
			JPanel exitPanel = new JPanel();
			datePanel.add(exitPanel, BorderLayout.EAST);
			
			JLabel lblExit = new JLabel("Exit Date");
			exitPanel.add(lblExit);
			
			JPanel exitDateField = new JPanel();
			exitPanel.add(exitDateField);

			exitDateField.add(exitDate);
			joiningDetails.setLayout(new BorderLayout(0, 0));
			joiningDetails.add(bullDetailsPanel, BorderLayout.NORTH);
			joiningDetails.add(datePanel);
			
			panel.add(jisp, BorderLayout.CENTER);
			
			if(mobID==-1){
				createMembersPanel(joiningID);
			}else{
				createMembersPanel(joiningID,mobID);
			}
			
			if(!valid){
				JPanel flow =new JPanel();
				JLabel label = new JLabel("Can not create a new Joining as no eligible Male cattle were found.");
				flow.add(label);
				panel.add(flow, BorderLayout.CENTER);
			}
			
		}else{
			panel.removeAll();
			panel.setLayout(new BorderLayout(0, 0));
			if(joiningID==0){
				viewing=JOINING_LIST;
				createMainPanel();
			}
			JPanel flow =new JPanel();
			JLabel label = new JLabel("No Such Joining can be found with the given internal id: "+joiningID+".");
			flow.add(label);
			panel.add(flow, BorderLayout.CENTER);
			return false;
		}
		validate();
		
		return true;
	}

	/**
	 * Create a list of members that belong to this Joining
	 * @param joiningID The long ID value that represents the Joining to show the Members for.
	 */
	private void createMembersPanel(long joiningID){
		createMembersPanel(joiningID,-1);
	}
	
	/**
	 * Create a list of existing members and members that can be added to this Joining
	 * @param joiningID The ID of the Joining.
	 * @param limitGroupID Select all eligible members from within this group.
	 */
	private void createMembersPanel(final long joiningID,final long limitGroupID){
		viewing = VIEW_MEMBER;
		membersListPanel.setLayout(new BorderLayout(0, 0));
		
		final int ADD		= 0;
		final int VISUAL	= 1;
		final int NLIS		= 2;
		final int RF		= 3;
		final int DOB 		= 4;
		final int ACTIVE	= 5;
		
		final Table bovinePanel = new Table("Members",false,
			"","Visual ID","NLIS","RF ID","DOB","Status");
		bovinePanel.setColumnVisible(ADD, false);
		bovinePanel.setEmptyMessage("There are no cattle in this Joining.");
		
		final Table bovineAddPanel = new Table("Select any of the following female cattle to add to this Joining.",true,
				"Add to Joining","Visual ID","NLIS","RF ID","DOB","Status");
		bovineAddPanel.setEmptyMessage("There are no female cattle eligible to add to this Joining.");
		
		new Thread(){
			@Override
			public void run(){
				bovinePanel.setHeaderOrderedBy(orderMemberListBy==LIST_ORDER_VISUAL?VISUAL:orderMemberListBy==LIST_ORDER_RF?RF:orderMemberListBy==LIST_ORDER_NLIS?NLIS:orderMemberListBy==LIST_ORDER_DOB?DOB:orderMemberListBy==LIST_ORDER_ACTIVE?ACTIVE:VISUAL, orderMemberHighToLow==1);
				bovinePanel.addHeaderMouseListener(VISUAL, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_VISUAL?-1:1);
						orderMemberListBy = LIST_ORDER_VISUAL;
						createMembersPanel(joiningID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				bovinePanel.addHeaderMouseListener(RF, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_RF?-1:1);
						orderMemberListBy = LIST_ORDER_RF;
						createMembersPanel(joiningID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				bovinePanel.addHeaderMouseListener(NLIS, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_NLIS?-1:1);
						orderMemberListBy = LIST_ORDER_NLIS;
						createMembersPanel(joiningID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				bovinePanel.addHeaderMouseListener(DOB, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_DOB?-1:1);
						orderMemberListBy = LIST_ORDER_DOB;
						createMembersPanel(joiningID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				bovinePanel.addHeaderMouseListener(ACTIVE, new MouseListener(){
					@Override
					public void mouseClicked(MouseEvent e) {
						orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_ACTIVE?-1:1);
						orderMemberListBy = LIST_ORDER_ACTIVE;
						createMembersPanel(joiningID);
					}
					@Override public void mousePressed(MouseEvent e) {}
					@Override public void mouseReleased(MouseEvent e) {}
					@Override public void mouseEntered(MouseEvent e) {}
					@Override public void mouseExited(MouseEvent e) {}
				});
				
				Join j = LivestockSolutions.getJoiningByID(joiningID);
				Bovine[] bList = j!=null?j.getCows():new Bovine[]{};
				
				Arrays.sort(bList, 
					orderMemberListBy==LIST_ORDER_VISUAL?
						orderMemberHighToLow==1?Comparators.bovineComparatorVISID:Collections.reverseOrder(Comparators.bovineComparatorVISID)
					:orderMemberListBy==LIST_ORDER_NLIS?
						orderMemberHighToLow==1?Comparators.bovineComparatorNLISID:Collections.reverseOrder(Comparators.bovineComparatorNLISID)
					:orderMemberListBy==LIST_ORDER_RF?
						orderMemberHighToLow==1?Comparators.bovineComparatorRFID:Collections.reverseOrder(Comparators.bovineComparatorRFID)
					:orderMemberListBy==LIST_ORDER_DOB?
						orderMemberHighToLow==1?Comparators.bovineComparatorDOB:Collections.reverseOrder(Comparators.bovineComparatorDOB)
					:orderMemberHighToLow==1?Comparators.bovineComparatorActive:Collections.reverseOrder(Comparators.bovineComparatorActive));

				for(int x=0; x<bList.length; x++){
					bovinePanel.addRow(
						null,
						new JLabel(bList[x].getEartag().getEartagID()),
						new JLabel(bList[x].getEartag().getNlisID()),
						new JLabel(bList[x].getEartag().getRfID()),
						new JLabel(bList[x].getDob()!=null?JDatePickerDate.format(bList[x].getDob()):"Unknown"),
						new JLabel(bList[x].isActive()?"Active":bList[x].getDeacquisition().getMethod()));

					final long id= bList[x].getID();
					bovinePanel.addMouseListener(new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							if(!MainFrame.getInstance().showBovine(id)) {
								//Show message not found?
							}
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
				}
				
				if(edit){
					bovineAddPanel.setHeaderOrderedBy(orderMemberListBy==LIST_ORDER_VISUAL?VISUAL:orderMemberListBy==LIST_ORDER_RF?RF:orderMemberListBy==LIST_ORDER_NLIS?NLIS:orderMemberListBy==LIST_ORDER_DOB?DOB:orderMemberListBy==LIST_ORDER_ACTIVE?ACTIVE:VISUAL, orderMemberHighToLow==1);
					bovineAddPanel.setHeaderClickable(ADD, false);
					bovineAddPanel.addHeaderMouseListener(VISUAL, new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_VISUAL?-1:1);
							orderMemberListBy = LIST_ORDER_VISUAL;
							createMembersPanel(joiningID,mobID);
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
					bovineAddPanel.addHeaderMouseListener(RF, new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_RF?-1:1);
							orderMemberListBy = LIST_ORDER_RF;
							createMembersPanel(joiningID,mobID);
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
					bovineAddPanel.addHeaderMouseListener(NLIS, new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_NLIS?-1:1);
							orderMemberListBy = LIST_ORDER_NLIS;
							createMembersPanel(joiningID,mobID);
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
					bovineAddPanel.addHeaderMouseListener(DOB, new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_DOB?-1:1);
							orderMemberListBy = LIST_ORDER_DOB;
							createMembersPanel(joiningID,mobID);
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
					bovineAddPanel.addHeaderMouseListener(ACTIVE, new MouseListener(){
						@Override
						public void mouseClicked(MouseEvent e) {
							orderMemberHighToLow = orderMemberHighToLow*(orderMemberListBy==LIST_ORDER_ACTIVE?-1:1);
							orderMemberListBy = LIST_ORDER_ACTIVE;
							createMembersPanel(joiningID,mobID);
						}
						@Override public void mousePressed(MouseEvent e) {}
						@Override public void mouseReleased(MouseEvent e) {}
						@Override public void mouseEntered(MouseEvent e) {}
						@Override public void mouseExited(MouseEvent e) {}
					});
					
					Group g = LivestockSolutions.getGroupByID(limitGroupID);
					Bovine[] allbalist = LivestockSolutions.getBovines(); // Get all Bovines
					ArrayList<Bovine> balist = g!=null?new ArrayList<Bovine>(Arrays.asList(g.getBovineList())):new ArrayList<Bovine>(); // Use a list of no filters.
					List<Cow> bAList = j!=null?Arrays.asList(j.getCows()):new ArrayList<Cow>();
					
					Arrays.sort(allbalist, 
						orderMemberListBy==LIST_ORDER_VISUAL?
							orderMemberHighToLow==1?Comparators.bovineComparatorVISID:Collections.reverseOrder(Comparators.bovineComparatorVISID)
						:orderMemberListBy==LIST_ORDER_NLIS?
							orderMemberHighToLow==1?Comparators.bovineComparatorNLISID:Collections.reverseOrder(Comparators.bovineComparatorNLISID)
						:orderMemberListBy==LIST_ORDER_RF?
							orderMemberHighToLow==1?Comparators.bovineComparatorRFID:Collections.reverseOrder(Comparators.bovineComparatorRFID)
						:orderMemberListBy==LIST_ORDER_DOB?
							orderMemberHighToLow==1?Comparators.bovineComparatorDOB:Collections.reverseOrder(Comparators.bovineComparatorDOB)
						:orderMemberHighToLow==1?Comparators.bovineComparatorActive:Collections.reverseOrder(Comparators.bovineComparatorActive));
					
					ArrayList<Bovine> barrList = new ArrayList<Bovine>(Arrays.asList(allbalist));
					
					Iterator<Bovine> i = barrList.iterator();
					while(i.hasNext()){
						Bovine b = i.next();
						if(!(b instanceof Cow) || bAList.contains(b) || !b.isActive()){
							i.remove();
						}
					}
					
					i = balist.iterator();
					while(i.hasNext()){
						Bovine b = i.next();
						if(!(b instanceof Cow) || bAList.contains(b) || !b.isActive()){
							i.remove();
						}
					}
					
					if(cowAddList.isEmpty()){
						cowAddList.addAll(Arrays.asList(balist.toArray(new Cow[balist.size()])));
					}
	
					for(int x=0; x<barrList.size(); x++){
						final JCheckBox add = new JCheckBox();
						// Set this Animal to selected if it is currently selected.
						add.setSelected(cowAddList.contains(barrList.get(x)));
						
						bovineAddPanel.addRow(
							add,
							new JLabel(barrList.get(x).getEartag().getEartagID()),
							new JLabel(barrList.get(x).getEartag().getNlisID()),
							new JLabel(barrList.get(x).getEartag().getRfID()),
							new JLabel(barrList.get(x).getDob()!=null?JDatePickerDate.format(barrList.get(x).getDob()):"Unknown"),
							new JLabel(barrList.get(x).isActive()?"Active":barrList.get(x).getDeacquisition().getMethod()));
	
						final Cow c = (Cow)barrList.get(x);
						bovineAddPanel.addMouseListener(new MouseListener(){
							@Override
							public void mouseClicked(MouseEvent e) {
								add.setSelected(!add.isSelected());
								if(add.isSelected()){
									cowAddList.add(c);
								}else{
									cowAddList.remove(c);
								}
							}
							@Override public void mousePressed(MouseEvent e) {}
							@Override public void mouseReleased(MouseEvent e) {}
							@Override public void mouseEntered(MouseEvent e) {}
							@Override public void mouseExited(MouseEvent e) {}
						});
						
						bovineAddPanel.addDefaultMouseListenerTo(add);
						add.addMouseListener(new MouseListener(){
							@Override
							public void mouseClicked(MouseEvent e) {
								if(add.isSelected()){
									cowAddList.add(c);
								}else{
									cowAddList.remove(c);
								}
							}
							@Override public void mousePressed(MouseEvent e) {}
							@Override public void mouseReleased(MouseEvent e) {}
							@Override public void mouseEntered(MouseEvent e) {}
							@Override public void mouseExited(MouseEvent e) {}
						});
						
						membersListPanel.add(bovineAddPanel, BorderLayout.CENTER);
					}
				}
				validate();
			}
		}.start();

		membersListPanel.removeAll();
		JPanel container1 = new JPanel();
		container1.setLayout(new BorderLayout(10,10));
		JPanel buttonPanel1 = new JPanel();
		((FlowLayout)buttonPanel1.getLayout()).setAlignment(FlowLayout.RIGHT);
		
		JButton btnNewMob = new JButton("Add Members");
		btnNewMob.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				edit=true;
				createJoiningPanel(joiningViewID,mobID);
			}
		});
		buttonPanel1.add(btnNewMob);
		container1.add(buttonPanel1,BorderLayout.NORTH);
		container1.add(bovinePanel,BorderLayout.CENTER);
		membersListPanel.add(container1,BorderLayout.NORTH);
	}

	@Override
	public long getID() {
		return joiningViewID;
	}
}
